﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleCompiler
{

    public class TypeBase
    {

    }
    public class TypeAny : TypeBase
    {

    }

    public class TypeNone : TypeAny
    {
        public static readonly TypeNone None = new TypeNone();
    }

    public enum TypeNotNoneName
    {
        Unknown,
        Int,
        Double,
        String,
        Bool
    }

    public class TypeNotNone : TypeAny
    {
        public static TypeNotNone NotLoaded = new TypeNotNone();
        public virtual TypeNotNone add(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        public virtual TypeNotNone sub(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }
        public virtual TypeNotNone mul(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }
        public virtual TypeNotNone div(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }
        public virtual TypeNotNone assign_from(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }
     
        internal static TypeNotNone CreateInstance(TypeNotNoneName value)
        {
            switch(value)
            {
                case TypeNotNoneName.Int:
                    return new TypeInt();
                    

                case TypeNotNoneName.Double:
                    return new TypeDouble();
                    

                case TypeNotNoneName.String:
                    return new TypeString();
                    

                case TypeNotNoneName.Bool:
                    return TypeBool.falseValue;
            }
            throw new InvalidOperationException();
        }

        internal virtual bool equals_to(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        internal virtual bool not_equals_to(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        internal virtual bool less_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        internal virtual bool less_equal_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        internal virtual bool great_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        internal virtual bool great_equal_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }



        public virtual TypeNotNone Copy()
        {
            return this;
        }

        public virtual string ValueString()
        {
            return "None";
        }


    }

    internal class TypeNumber : TypeNotNone
    {
        
    }

    internal class TypeInt : TypeNumber
    {
        public Int64 value = 0;
        public TypeInt(Int64 inValue = 0)
        {
            value = inValue;
        }

        public override TypeNotNone add(TypeNotNone value)
        {
            return new TypeInt(this.value + ((TypeInt)value).value);
        }

        public override TypeNotNone sub(TypeNotNone value)
        {
            return new TypeInt(this.value - ((TypeInt)value).value);
        }
        public override TypeNotNone mul(TypeNotNone value)
        {
            return new TypeInt(this.value * ((TypeInt)value).value);
        }
        public override TypeNotNone div(TypeNotNone value)
        {
            return new TypeInt(this.value / ((TypeInt)value).value);
        }

        public override TypeNotNone assign_from(TypeNotNone value)
        {
            this.value = ((TypeInt)value).value;
            return TypeNotNone.NotLoaded;
        }

        internal override bool equals_to(TypeNotNone value)
        {
            return this.value == ((TypeInt)value).value;
        }

        internal override bool not_equals_to(TypeNotNone value)
        {
            return this.value != ((TypeInt)value).value;
        }

        internal override bool less_than(TypeNotNone value)
        {
            return this.value < ((TypeInt)value).value;
        }

        internal override bool less_equal_than(TypeNotNone value)
        {
            return this.value <= ((TypeInt)value).value;
        }

        internal override bool great_than(TypeNotNone value)
        {
            return this.value > ((TypeInt)value).value;
        }

        internal override bool great_equal_than(TypeNotNone value)
        {
            return this.value >= ((TypeInt)value).value;
        }


        public override TypeNotNone Copy()
        {
            return new TypeInt(value);
        }

        public override string ValueString()
        {
            return $"[int]{value}";
        }
    }

    internal class TypeDouble : TypeNumber
    {
        public double value = 0.0;
        public TypeDouble(double inValue = 0.0)
        {
            value = inValue;
        }

        public override TypeNotNone add(TypeNotNone value)
        {
            return new TypeDouble(this.value + ((TypeDouble)value).value);
        }

        public override TypeNotNone sub(TypeNotNone value)
        {
            return new TypeDouble(this.value - ((TypeDouble)value).value);
        }
        public override TypeNotNone mul(TypeNotNone value)
        {
            return new TypeDouble(this.value * ((TypeDouble)value).value);
        }
        public override TypeNotNone div(TypeNotNone value)
        {
            return new TypeDouble(this.value / ((TypeDouble)value).value);
        }

        public override TypeNotNone assign_from(TypeNotNone value)
        {
            this.value = ((TypeInt)value).value;
            return TypeNotNone.NotLoaded;
        }

        internal override bool equals_to(TypeNotNone value)
        {
            return this.value == ((TypeDouble)value).value;
        }

        internal override bool not_equals_to(TypeNotNone value)
        {
            return this.value != ((TypeDouble)value).value;
        }

        internal override bool less_than(TypeNotNone value)
        {
            return this.value < ((TypeDouble)value).value;
        }

        internal override bool less_equal_than(TypeNotNone value)
        {
            return this.value <= ((TypeDouble)value).value;
        }

        internal override bool great_than(TypeNotNone value)
        {
            return this.value > ((TypeDouble)value).value;
        }

        internal override bool great_equal_than(TypeNotNone value)
        {
            return this.value >= ((TypeDouble)value).value;
        }

        public override TypeNotNone Copy()
        {
            return new TypeDouble(value);
        }

        public override string ValueString()
        {
            return $"[double]{value}";
        }
    }

    internal class TypeString : TypeNotNone
    {
        public string value = "";
        public TypeString(string inValue = "")
        {
            value = inValue;
        }

        public override TypeNotNone add(TypeNotNone value)
        {
            return new TypeString($"{this.value}{((TypeString)value).value}");
        }

        public override TypeNotNone sub(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }
        public override TypeNotNone mul(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }
        public override TypeNotNone div(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        public override TypeNotNone assign_from(TypeNotNone value)
        {
            this.value = $"{((TypeString)value).value}";
            return TypeNotNone.NotLoaded;
        }

        internal override bool equals_to(TypeNotNone value)
        {
            return this.value == ((TypeString)value).value;
        }

        internal override bool not_equals_to(TypeNotNone value)
        {
            return this.value != ((TypeString)value).value;
        }

        internal override bool less_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        internal override bool less_equal_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        internal override bool great_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        internal override bool great_equal_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        public override TypeNotNone Copy()
        {
            return new TypeString($"{value}");
        }

        public override string ValueString()
        {
            return $"[string]{value}";
        }
    }

    internal class TypeBool : TypeNotNone
    {
        public Boolean value = false;
        public static readonly TypeBool trueValue = new TypeBool() { value = true};
        public static readonly TypeBool falseValue = new TypeBool() { value = false };

        public override TypeNotNone add(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        public override TypeNotNone sub(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }
        public override TypeNotNone mul(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }
        public override TypeNotNone div(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        public override TypeNotNone assign_from(TypeNotNone value)
        {
            this.value = ((TypeBool)value).value;
            return TypeNotNone.NotLoaded;
        }

        internal override bool equals_to(TypeNotNone value)
        {
            return this.value == ((TypeBool)value).value;
        }

        internal override bool not_equals_to(TypeNotNone value)
        {
            return this.value != ((TypeBool)value).value;
        }

        internal override bool less_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        internal override bool less_equal_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        internal override bool great_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }

        internal override bool great_equal_than(TypeNotNone value)
        {
            throw new InvalidOperationException();
        }
        public override TypeNotNone Copy()
        {
            return new TypeBool() { value = this.value};
        }

        public override string ValueString()
        {
            return $"[bool]{value}";
        }
    }
}
